package it.trekker.activities;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import it.trekker.R;
import it.trekker.gps.service.GPSLocationService;
import it.trekker.sensors.OrientationCoord;
import it.trekker.sensors.SensorsListenerService;
import it.trekker.statistics.RealTimeStatistics;
import it.trekker.statistics.GPSStatistics;
import it.trekker.statistics.RealTimeStatistics.AltitudeDifferenceObject;
import it.trekker.step.StepDetector;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.widget.TextView;

public class RealTimeStatisticsActivity extends Activity {
	
	private static final String TAG = RealTimeStatisticsActivity.class.getSimpleName();
	
	// GUI components
	private TextView date_tv = null;
	private TextView pace_tv = null;
	private TextView compass_tv = null;
	private TextView altitude_tv = null;
	private TextView differenceTot_tv = null;
	private TextView differenceUp_tv = null;
	private TextView differenceDown_tv = null;
	private TextView distance_tv = null;
	private TextView steps_tv = null;
	
	private SharedPreferences sharedPref = null;
	private boolean stepCounterEnabled;
	
	// Service components
	private GPSLocationService gpsLocationService = null;
	private SensorsListenerService sensorsService = null;
	private RealTimeStatistics statisticsFromStartPoint = null;	// Shared RealTimeStatistics (shared with ExcursionMainActivity) 
	private StepDetector stepDetector = null;
	private ServiceConnection gpsServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			gpsLocationService = null;
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			gpsLocationService = ((GPSLocationService.GPSBinder)service).getService();
			gpsLocationService.addGPSListener(statisticsFromStartPoint);
		}
	};
	private ServiceConnection sensorsServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			sensorsService = null;
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			sensorsService = ((SensorsListenerService.SensorsBinder)service).getService();
			sensorsService.addOrientationListener(statisticsFromStartPoint);
			if(stepCounterEnabled)
				sensorsService.addAccelerometerListener(stepDetector);
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.realtime_statistics_layout);
		
		loadPreferences();
		
		date_tv = (TextView) findViewById(R.id.stat_date);
		pace_tv = (TextView) findViewById(R.id.stat_pace);
		compass_tv = (TextView) findViewById(R.id.stat_compass);
		altitude_tv = (TextView) findViewById(R.id.stat_altitude);
		differenceTot_tv = (TextView) findViewById(R.id.stat_difference_tot);
		differenceUp_tv = (TextView) findViewById(R.id.stat_difference_up);
		differenceDown_tv = (TextView) findViewById(R.id.stat_difference_down);
		distance_tv = (TextView) findViewById(R.id.stat_distance);
		steps_tv = (TextView) findViewById(R.id.stat_steps);
		
		Calendar cal = Calendar.getInstance();
		date_tv.setText(new SimpleDateFormat("dd/MM/yyyy").format(cal.getTime()));
		
		// Shared RealTimeStatistics (shared with ExcursionMainActivity) 
		statisticsFromStartPoint = RealTimeStatistics.getSharedInstance();
		statisticsFromStartPoint.registerCallback(statisticsCallback);
		
		
		Intent gpsIntent = new Intent(this, GPSLocationService.class);
		getApplicationContext().bindService(gpsIntent, gpsServiceConnection, Context.BIND_AUTO_CREATE);

		Intent sensorsIntent = new Intent(this, SensorsListenerService.class);
		getApplicationContext().bindService(sensorsIntent, sensorsServiceConnection, Context.BIND_AUTO_CREATE);
		
		if(stepCounterEnabled) {
			stepDetector = new StepDetector();
			stepDetector.addListener(statisticsFromStartPoint);
		}
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	protected void onPause() {
		super.onPause();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		getApplicationContext().unbindService(gpsServiceConnection);
		statisticsFromStartPoint.removeCallback(statisticsCallback);
		
		getApplicationContext().unbindService(sensorsServiceConnection);

		if(stepCounterEnabled) {
			stepDetector.removeListener(statisticsFromStartPoint);
		}
	}
	
	// Back key pression handled by the parent (ExcursionMainActivity tabactivity)
	@Override 
	public void onBackPressed() { 
		this.getParent().onBackPressed();
	}
	
//	@Override
//	public void onConfigurationChanged(Configuration newConfig) {
//		super.onConfigurationChanged(newConfig);
//	}
	
	
	
	
	
	
	//***********************************************************************//
	//*************************** Utility methods ***************************//
	//***********************************************************************//

	
	private void loadPreferences() {
		sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
		
		stepCounterEnabled = sharedPref.getBoolean("step_counter_enabled", true);
	}
	
	
	
	
	
	
	//**********************************************************************//
	//************ Callback and message handler to update views ************//
	//**********************************************************************//
	
	
	private static final int PACE_MSG = 0;
	private static final int ALTITUDE_MSG = 1;
	private static final int ALTDIFF_MSG = 2;
	private static final int DISTANCE_MSG = 3;
	private static final int STEPS_MSG = 4;
	private static final int ORIENTATION_MSG = 5;
	
	private RealTimeStatistics.IRealTimeCallback statisticsCallback = new RealTimeStatistics.IRealTimeCallback() {

		@Override
		public void paceChanged(double value) {
			// value*1000 to preserve decimal digits
			mHandler.sendMessage(mHandler.obtainMessage(PACE_MSG, (int)(value*1000), 0));
		}

		@Override
		public void distanceChanged(double value) {
			mHandler.sendMessage(mHandler.obtainMessage(DISTANCE_MSG, (int)(value*1000), 0));
		}

		@Override
		public void altitudeChanged(double value) {
			mHandler.sendMessage(mHandler.obtainMessage(ALTITUDE_MSG, (int)(value*1000), 0));
		}

		@Override
		public void altitudeDifferenceChanged(AltitudeDifferenceObject diff) {
			mHandler.sendMessage(mHandler.obtainMessage(ALTDIFF_MSG, diff));
		}

		@Override
		public void stepsChanged(long value) {
			Long steps = new Long(value);
			mHandler.sendMessage(mHandler.obtainMessage(STEPS_MSG, steps));
		}

		@Override
		public void orientationChanged(OrientationCoord orientation) {
			mHandler.sendMessage(mHandler.obtainMessage(ORIENTATION_MSG, orientation));
		}
       
    };
	
	
	private Handler mHandler = new Handler() {
		@Override 
		public void handleMessage(Message msg) {
			
            switch (msg.what) {
            
	            case PACE_MSG:
	            	String pace_str;
	            	if(msg.arg1 == GPSStatistics.UNDEFINED_PACE*1000) {
	            		pace_str = "-";
	            	}
	            	else {
	            		double pace_val = (msg.arg1/1000f);
	            		pace_str = String.format("%.2f", pace_val);
	            	}
	            	pace_tv.setText(pace_str);
	            	break;
	            	
	            case ALTITUDE_MSG:
	            	String altitude_str;
	            	if(msg.arg1 == GPSStatistics.UNDEFINED_ALTITUDE*1000) {
	            		altitude_str = "-";
	            	}
	            	else {
	            		double altitude_val = (msg.arg1/1000f);
	            		altitude_str = String.format("%.2f", altitude_val);
	            	}
	            	altitude_tv.setText(altitude_str);
	            	break;
	            	
	            case ALTDIFF_MSG:
	            	AltitudeDifferenceObject diff = (AltitudeDifferenceObject) msg.obj;
	            	differenceTot_tv.setText(String.format("%+.2f", diff.totAltitudeDifference));	// m
	            	differenceUp_tv.setText(String.format("%+.2f", diff.upAltitudeDifference));	// m
	            	differenceDown_tv.setText(String.format("%+.2f", diff.downAltitudeDifference));	// m
	            	break;
	            	
	            case DISTANCE_MSG:
	            	double distance_val = (msg.arg1/1000f);
	            	distance_tv.setText(String.format("%.3f", distance_val/1000));	// Km
	            	break;
	            	
                case STEPS_MSG:
//                	int steps_val = msg.arg1;
//	            	steps_tv.setText(steps_val);
                	Long stepsValue = (Long) msg.obj;
                	steps_tv.setText(String.valueOf(stepsValue.longValue()));
                    break;
                    
                case ORIENTATION_MSG:
                	OrientationCoord orientation = (OrientationCoord) msg.obj;
                	compass_tv.setText(orientation.getCompassString());
                    break;
                    
                default:
                    super.handleMessage(msg);
            }
        }
	};
	
	
}
